#pragma once

#include <iostream>
#include <memory>
#include <jsoncpp/json/json.h>

#define SelfDefine 1

namespace Protocol
{
    const std::string Protseq = " ";
    const std::string LineBreakseq = "\n";

    // 发送报文
    // 发送时能够保证是一个完整的报文
    std::string Encode(const std::string &message)
    {
        std::string len = std::to_string(message.size());
        std::string package = len + LineBreakseq + message + LineBreakseq;
        return package;
    }

    // 接收报文
    // 接收时不能保证是一个完整的报文
    // 分为以下几种情况

    // 1.  "l
    // 2.  "len
    // 3.  "len\n"
    // 4.  "len\nx"
    // 5.  "len\nx op"
    // 6.  "len\nx op y"
    // 7.  "len\nx op y\n"
    // 8.  "len\nx op y\n""len
    // 9.  "len\nx op y\n""len\n"
    // 10. "len\nx op y\n""len\nx"
    // 11. "len\nx op y\n""len\nx op"
    // 12. "len\nx op y\n""len\nx op y"
    // 13. "len\nx op y\n""len\nx op y\n"

    bool Decode(std::string &package, std::string *message)
    {
        // "len\nx op y\n"

        auto pos = package.find(LineBreakseq); // 寻找报文中的第一个 '\n'

        if (pos == std::string::npos)
        {
            return false;
        }

        std::string lens = package.substr(0, pos); // 截取报文中的 len
        std::cout<<lens<<std::endl;
        int messagelen = std::stoi(lens);          // 计算报文中 len 的长度

        // "len\nx op y\,"
        // 一个完整报文的总长度等于 len 的长度 + "x op y"的长度 + 两个 '\n'(分隔符) 的长度
        // "x op y"的长度 == 最前面的len的值
        int total = lens.size() + messagelen + 2 * LineBreakseq.size();

        // 如果当前报文的总长度不满足一个报文的的基本长度，就返回0
        if (package.size() < total)
        {

            return false;
        }
        // 满足最小单位，那么将结果返回给 message ,一次只读取一个单位的报文长度
        *message = package.substr(pos + LineBreakseq.size(), messagelen);

        // 读取后将package中读取过的报文删除
        package.erase(0, total);
        return true;
    }

    class Request
    {
        int _data_x, _data_y;
        char _oper;

    public:
        Request() : _data_x(0), _data_y(0), _oper('0') {}
        Request(int x, int y, char op) : _data_x(x), _data_y(y), _oper(op)
        {
        }

        ~Request() {}

        int Get_data_x()
        {
            return _data_x;
        }

        int Get_data_y()
        {
            return _data_y;
        }

        char Get_oper()
        {
            return _oper;
        }

        void Debug()
        {
            std::cout << "_data_x:"
                      << "  _oper:" << _oper << _data_x << "  _data_y:" << _data_y << std::endl;
        }

        std::string DebugPrint()
        {
            return std::string(std::to_string(_data_x) + " " + _oper + " " + std::to_string(_data_y));
        }

        void Inc()
        {
            _data_x++;
            _data_y++;
        }

        // 序列化
        bool Serialize(std::string *out)
        {
#ifdef SelfDefine
            *out = std::to_string(_data_x) + Protseq + _oper + Protseq + std::to_string(_data_y);
            return true;
#else
            Json::Value _json;
            _json["_data_x"] = _data_x;
            _json["_data_y"] = _data_y;
            _json["_oper"] = _oper;

            *out = Json::FastWriter().write(_json);
            return true;
#endif
        }

        // 反序列化
        bool DeSerialize(std::string &in)
        {
#ifdef SelfDefine
            auto left = in.find(Protseq);
            if (left == std::string::npos)
                return false;

            auto right = in.rfind(Protseq); // 从右侧找
            if (right == std::string::npos)
                return false;

            _data_x = std::stoi(in.substr(0, left));
            _data_y = std::stoi(in.substr(right + Protseq.size()));

            std::string oper = in.substr(left + Protseq.size(), right - (left + Protseq.size()));
            if (oper.size() != 1)
                return false;

            _oper = oper[0];
            return true;
#else
            Json::Value _json;
            Json::Reader reader;
            bool res = reader.parse(in, _json);
            if (res)
            {
                _data_x = _json["_data_x"].asInt();
                _data_y = _json["_data_y"].asInt();
                _oper = _json["_data_y"].asInt(); // 字符本质上也是 Int
                return true;
            }
            return false;

#endif
        }
    };

    class Response
    {
        int _result, _code; //_code 状态码
    public:
        Response() : _result(0), _code(0) {}
        Response(int result, int code) : _result(result), _code(code)
        {
        }

        ~Response() {}

        void Set_result(int result)
        {
            _result = result;
        }

        void Set_code(int code)
        {
            _code = code;
        }

        int Get_result()
        {
            return _result;
        }

        int Get_code()
        {
            return _code;
        }

        // 序列化
        bool
        Serialize(std::string *out)
        {
#ifdef SelfDefine
            *out = std::to_string(_result) + Protseq + std::to_string(_code);
            return true;
#else
            Json::Value _json;
            _json["_result"] = _result;
            _json["_code"] = _code;

            *out = Json::FastWriter().write(_json);
            return true;
#endif
        }

        // 反序列化
        bool DeSerialize(std::string &in) //"x op y"
        {

#ifdef SelfDefine
            
            auto pos = in.find(Protseq);
            if (pos == std::string::npos)
                return false;

            _result = std::stoi(in.substr(0, pos));
            _code = std::stoi(in.substr(pos + Protseq.size()));
            return true;
#else
            Json::Value _json;
            Json::Reader reader;
            int res = reader.parse(in, _json);

            if (res)
            {
                _result = _json["_result"].asInt();
                _code = _json["_code"].asInt();
                return true;
            }
            return false;
#endif
        }
    };

    // 工厂模式
    class Factory
    {
    public:
        std::shared_ptr<Request> BuildRequest()
        {
            return std::make_shared<Request>();
        }
        std::shared_ptr<Request> BuildRequest(int x, int y, char op)
        {
            return std::make_shared<Request>(x, y, op);
        }

        std::shared_ptr<Response> BuildResponse()
        {
            return std::make_shared<Response>();
        }

        std::shared_ptr<Response> BuildResponse(int result, int code)
        {
            return std::make_shared<Response>(result, code);
        }
    };
}